/*********************************************************************
 * Copyright (C) 2002 Andrew Khan
 * <p>
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * <p>
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * <p>
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ***************************************************************************/

package jxl.biff;

import jxl.common.Assert;
import jxl.common.Logger;

/**
 * Contains the common data for a compound file
 */
public abstract class BaseCompoundFile {
    /**
     * The logger
     */
    private static Logger logger = Logger.getLogger(BaseCompoundFile.class);

    /**
     * The identifier at the beginning of every OLE file
     */
    protected static final byte[] IDENTIFIER = new byte[]
            {(byte) 0xd0,
                    (byte) 0xcf,
                    (byte) 0x11,
                    (byte) 0xe0,
                    (byte) 0xa1,
                    (byte) 0xb1,
                    (byte) 0x1a,
                    (byte) 0xe1};
    /**
     */
    protected static final int NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c;
    /**
     */
    protected static final int SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c;
    /**
     */
    protected static final int NUM_SMALL_BLOCK_DEPOT_BLOCKS_POS = 0x40;
    /**
     */
    protected static final int ROOT_START_BLOCK_POS = 0x30;
    /**
     */
    protected static final int BIG_BLOCK_SIZE = 0x200;
    /**
     */
    protected static final int SMALL_BLOCK_SIZE = 0x40;
    /**
     */
    protected static final int EXTENSION_BLOCK_POS = 0x44;
    /**
     */
    protected static final int NUM_EXTENSION_BLOCK_POS = 0x48;
    /**
     */
    protected static final int PROPERTY_STORAGE_BLOCK_SIZE = 0x80;
    /**
     */
    protected static final int BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c;
    /**
     */
    protected static final int SMALL_BLOCK_THRESHOLD = 0x1000;

    // property storage offsets
    /**
     */
    private static final int SIZE_OF_NAME_POS = 0x40;
    /**
     */
    private static final int TYPE_POS = 0x42;
    /**
     */
    private static final int COLOUR_POS = 0x43;
    /**
     */
    private static final int PREVIOUS_POS = 0x44;
    /**
     */
    private static final int NEXT_POS = 0x48;
    /**
     */
    private static final int CHILD_POS = 0x4c;
    /**
     */
    private static final int START_BLOCK_POS = 0x74;
    /**
     */
    private static final int SIZE_POS = 0x78;

    /**
     * The standard property sets
     */
    public final static String ROOT_ENTRY_NAME = "Root Entry";
    public final static String WORKBOOK_NAME = "Workbook";
    public final static String SUMMARY_INFORMATION_NAME =
            "\u0005SummaryInformation";
    public final static String DOCUMENT_SUMMARY_INFORMATION_NAME =
            "\u0005DocumentSummaryInformation";
    public final static String COMP_OBJ_NAME =
            "\u0001CompObj";
    public final static String[] STANDARD_PROPERTY_SETS =
            new String[]{ROOT_ENTRY_NAME, WORKBOOK_NAME,
                    SUMMARY_INFORMATION_NAME,
                    DOCUMENT_SUMMARY_INFORMATION_NAME};

    /**
     * Property storage types
     */
    public final static int NONE_PS_TYPE = 0;
    public final static int DIRECTORY_PS_TYPE = 1;
    public final static int FILE_PS_TYPE = 2;
    public final static int ROOT_ENTRY_PS_TYPE = 5;


    /**
     * Inner class to represent the property storage sets.  Access is public
     * to allow access from the PropertySetsReader demo utility
     */
    public class PropertyStorage {
        /**
         * The name of this property set
         */
        public String name;
        /**
         * The type of the property set
         */
        public int type;
        /**
         * The colour of the property set
         */
        public int colour;
        /**
         * The block number in the stream which this property sets starts at
         */
        public int startBlock;
        /**
         * The size, in bytes, of this property set
         */
        public int size;
        /**
         * The previous property set
         */
        public int previous;
        /**
         * The next property set
         */
        public int next;
        /**
         * The child for this property set
         */
        public int child;

        /**
         * The data that created this set
         */
        public byte[] data;

        /**
         * Constructs a property set
         *
         * @param d the bytes
         */
        public PropertyStorage(byte[] d) {
            data = d;
            int nameSize = IntegerHelper.getInt(data[SIZE_OF_NAME_POS],
                    data[SIZE_OF_NAME_POS + 1]);

            if (nameSize > SIZE_OF_NAME_POS) {
                logger.warn("property set name exceeds max length - truncating");
                nameSize = SIZE_OF_NAME_POS;

            }
            type = data[TYPE_POS];
            colour = data[COLOUR_POS];

            startBlock = IntegerHelper.getInt
                    (data[START_BLOCK_POS],
                            data[START_BLOCK_POS + 1],
                            data[START_BLOCK_POS + 2],
                            data[START_BLOCK_POS + 3]);
            size = IntegerHelper.getInt
                    (data[SIZE_POS],
                            data[SIZE_POS + 1],
                            data[SIZE_POS + 2],
                            data[SIZE_POS + 3]);
            previous = IntegerHelper.getInt
                    (data[PREVIOUS_POS],
                            data[PREVIOUS_POS + 1],
                            data[PREVIOUS_POS + 2],
                            data[PREVIOUS_POS + 3]);
            next = IntegerHelper.getInt
                    (data[NEXT_POS],
                            data[NEXT_POS + 1],
                            data[NEXT_POS + 2],
                            data[NEXT_POS + 3]);
            child = IntegerHelper.getInt
                    (data[CHILD_POS],
                            data[CHILD_POS + 1],
                            data[CHILD_POS + 2],
                            data[CHILD_POS + 3]);

            int chars = 0;
            if (nameSize > 2) {
                chars = (nameSize - 1) / 2;
            }

            StringBuffer n = new StringBuffer("");
            for (int i = 0; i < chars; i++) {
                n.append((char) data[i * 2]);
            }

            name = n.toString();
        }

        /**
         * Constructs an empty property set.  Used when writing the file
         *
         * @param name the property storage name
         */
        public PropertyStorage(String name) {
            data = new byte[PROPERTY_STORAGE_BLOCK_SIZE];

            Assert.verify(name.length() < 32);

            IntegerHelper.getTwoBytes((name.length() + 1) * 2,
                    data,
                    SIZE_OF_NAME_POS);
            // add one to the name length to allow for the null character at
            // the end
            for (int i = 0; i < name.length(); i++) {
                data[i * 2] = (byte) name.charAt(i);
            }
        }

        /**
         * Sets the type
         *
         * @param t the type
         */
        public void setType(int t) {
            type = t;
            data[TYPE_POS] = (byte) t;
        }

        /**
         * Sets the number of the start block
         *
         * @param sb the number of the start block
         */
        public void setStartBlock(int sb) {
            startBlock = sb;
            IntegerHelper.getFourBytes(sb, data, START_BLOCK_POS);
        }

        /**
         * Sets the size of the file
         *
         * @param s the size
         */
        public void setSize(int s) {
            size = s;
            IntegerHelper.getFourBytes(s, data, SIZE_POS);
        }

        /**
         * Sets the previous block
         *
         * @param prev the previous block
         */
        public void setPrevious(int prev) {
            previous = prev;
            IntegerHelper.getFourBytes(prev, data, PREVIOUS_POS);
        }

        /**
         * Sets the next block
         *
         * @param nxt the next block
         */
        public void setNext(int nxt) {
            next = nxt;
            IntegerHelper.getFourBytes(next, data, NEXT_POS);
        }

        /**
         * Sets the child
         *
         * @param dir the child
         */
        public void setChild(int dir) {
            child = dir;
            IntegerHelper.getFourBytes(child, data, CHILD_POS);
        }

        /**
         * Sets the colour
         *
         * @param col colour
         */
        public void setColour(int col) {
            colour = col == 0 ? 0 : 1;
            data[COLOUR_POS] = (byte) colour;
        }

    }

    /**
     * Constructor
     */
    protected BaseCompoundFile() {
    }

}




